---
title: "系统编程基础"
description: "从 JavaScript 视角学习 C 语言系统编程，理解进程、线程、信号、系统调用，并对比 JavaScript 运行时环境。"
---

# 系统编程基础

## 1. 概念介绍

### 从 JavaScript 运行时到 C 系统编程

在 JavaScript 中，你在运行时环境中工作，该环境抽象了系统级操作。而在 C 语言中，你可以直接访问操作系统，允许你创建进程、处理信号和进行系统调用。

> 💡 **核心概念**：C 系统编程给你对操作系统的底层控制，使你能够构建系统工具、守护进程和高性能应用程序。

## 2. 进程和进程管理

<UniversalEditor title="进程创建" compare={true}>
```javascript !! js
// JavaScript - 进程管理 (Node.js)
const { spawn, exec } = require('child_process');

// 生成新进程
const child = spawn('ls', ['-la'], {
    stdio: 'inherit'
});

child.on('close', (code) => {
    console.log(`子进程退出，代码: ${code}`);
});

// 执行命令
exec('echo "来自子进程的问候"', (error, stdout, stderr) => {
    if (error) {
        console.error(`错误: ${error}`);
        return;
    }
    console.log(`输出: ${stdout}`);
});

// 进程信息
console.log('进程 ID:', process.pid);
console.log('父进程 ID:', process.ppid);
console.log('平台:', process.platform);
```

```c !! c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>

int main() {
    pid_t pid;
    
    printf("父进程 ID: %d\n", getpid());
    
    // 创建新进程
    pid = fork();
    
    if (pid < 0) {
        // fork 失败
        perror("fork 失败");
        exit(1);
    } else if (pid == 0) {
        // 子进程
        printf("子进程 ID: %d\n", getpid());
        printf("子进程的父进程 ID: %d\n", getppid());
        
        // 执行命令
        execlp("ls", "ls", "-la", NULL);
        
        // 如果 execlp 返回，说明有错误
        perror("execlp 失败");
        exit(1);
    } else {
        // 父进程
        printf("父进程等待子进程 %d\n", pid);
        
        int status;
        wait(&status);
        
        if (WIFEXITED(status)) {
            printf("子进程退出，状态: %d\n", WEXITSTATUS(status));
        }
    }
    
    return 0;
}
```
</UniversalEditor>

## 3. 线程和并发

<UniversalEditor title="线程" compare={true}>
```javascript !! js
// JavaScript - 线程 (Node.js Worker Threads)
const { Worker, isMainThread, parentPort, workerData } = require('worker_threads');

if (isMainThread) {
    // 主线程
    const worker = new Worker(__filename, {
        workerData: { number: 42 }
    });
    
    worker.on('message', (result) => {
        console.log('来自工作线程的结果:', result);
    });
    
    worker.on('error', (error) => {
        console.error('工作线程错误:', error);
    });
    
    worker.on('exit', (code) => {
        if (code !== 0) {
            console.error(`工作线程停止，退出代码: ${code}`);
        }
    });
} else {
    // 工作线程
    const result = workerData.number * 2;
    parentPort.postMessage(result);
}

// 异步/等待并发
async function concurrentTasks() {
    const promises = [
        new Promise(resolve => setTimeout(() => resolve('任务 1'), 1000)),
        new Promise(resolve => setTimeout(() => resolve('任务 2'), 500)),
        new Promise(resolve => setTimeout(() => resolve('任务 3'), 1500))
    ];
    
    const results = await Promise.all(promises);
    console.log('所有任务完成:', results);
}

concurrentTasks();
```

```c !! c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>

// 线程函数
void* threadFunction(void* arg) {
    int threadId = *(int*)arg;
    printf("线程 %d 开始\n", threadId);
    
    // 模拟工作
    sleep(1);
    
    printf("线程 %d 结束\n", threadId);
    return NULL;
}

// 带共享数据的线程
int sharedCounter = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void* incrementCounter(void* arg) {
    int iterations = *(int*)arg;
    
    for (int i = 0; i < iterations; i++) {
        pthread_mutex_lock(&mutex);
        sharedCounter++;
        pthread_mutex_unlock(&mutex);
    }
    
    return NULL;
}

int main() {
    pthread_t threads[3];
    int threadIds[3] = {1, 2, 3};
    
    // 创建线程
    for (int i = 0; i < 3; i++) {
        if (pthread_create(&threads[i], NULL, threadFunction, &threadIds[i]) != 0) {
            perror("创建线程失败");
            return 1;
        }
    }
    
    // 等待线程完成
    for (int i = 0; i < 3; i++) {
        pthread_join(threads[i], NULL);
    }
    
    printf("所有线程完成\n");
    
    // 带共享数据的线程
    pthread_t counterThreads[2];
    int iterations = 1000;
    
    for (int i = 0; i < 2; i++) {
        pthread_create(&counterThreads[i], NULL, incrementCounter, &iterations);
    }
    
    for (int i = 0; i < 2; i++) {
        pthread_join(counterThreads[i], NULL);
    }
    
    printf("最终计数器值: %d\n", sharedCounter);
    
    return 0;
}
```
</UniversalEditor>

## 4. 信号处理

<UniversalEditor title="信号处理" compare={true}>
```javascript !! js
// JavaScript - 信号处理 (Node.js)
process.on('SIGINT', () => {
    console.log('收到 SIGINT (Ctrl+C)');
    console.log('正在清理...');
    process.exit(0);
});

process.on('SIGTERM', () => {
    console.log('收到 SIGTERM');
    console.log('优雅关闭...');
    process.exit(0);
});

process.on('uncaughtException', (error) => {
    console.error('未捕获的异常:', error);
    process.exit(1);
});

// 自定义信号处理
let cleanupDone = false;

function cleanup() {
    if (!cleanupDone) {
        console.log('执行清理...');
        cleanupDone = true;
    }
}

process.on('exit', (code) => {
    cleanup();
    console.log(`进程退出，代码: ${code}`);
});

// 模拟一些工作
console.log('进程已启动。按 Ctrl+C 停止。');
setInterval(() => {
    console.log('工作中...');
}, 1000);
```

```c !! c
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

volatile sig_atomic_t flag = 0;

// 信号处理函数
void signalHandler(int sig) {
    if (sig == SIGINT) {
        printf("\n收到 SIGINT (Ctrl+C)\n");
        printf("正在清理...\n");
        flag = 1;
    } else if (sig == SIGTERM) {
        printf("收到 SIGTERM\n");
        printf("优雅关闭...\n");
        flag = 1;
    }
}

// 清理函数
void cleanup() {
    printf("执行清理...\n");
    // 在此添加清理代码
}

int main() {
    // 设置信号处理器
    if (signal(SIGINT, signalHandler) == SIG_ERR) {
        perror("设置 SIGINT 处理器失败");
        return 1;
    }
    
    if (signal(SIGTERM, signalHandler) == SIG_ERR) {
        perror("设置 SIGTERM 处理器失败");
        return 1;
    }
    
    printf("进程已启动。按 Ctrl+C 停止。\n");
    printf("进程 ID: %d\n", getpid());
    
    // 主循环
    while (!flag) {
        printf("工作中...\n");
        sleep(1);
    }
    
    cleanup();
    printf("进程退出\n");
    
    return 0;
}
```
</UniversalEditor>

## 5. 系统调用和文件操作

<UniversalEditor title="系统调用" compare={true}>
```javascript !! js
// JavaScript - 文件系统操作 (Node.js)
const fs = require('fs');
const path = require('path');

// 文件操作
fs.writeFileSync('test.txt', '你好，世界！');
const content = fs.readFileSync('test.txt', 'utf8');
console.log('文件内容:', content);

// 目录操作
fs.mkdirSync('testdir', { recursive: true });
const files = fs.readdirSync('.');
console.log('当前目录中的文件:', files);

// 文件统计
const stats = fs.statSync('test.txt');
console.log('文件大小:', stats.size);
console.log('是文件:', stats.isFile());
console.log('是目录:', stats.isDirectory());

// 进程信息
console.log('当前工作目录:', process.cwd());
console.log('环境变量:', process.env.PATH);

// 清理
fs.unlinkSync('test.txt');
fs.rmdirSync('testdir');
```

```c !! c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>

int main() {
    // 使用系统调用进行文件操作
    int fd = open("test.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (fd == -1) {
        perror("open 失败");
        return 1;
    }
    
    const char* message = "你好，世界！";
    ssize_t bytes_written = write(fd, message, strlen(message));
    if (bytes_written == -1) {
        perror("write 失败");
        close(fd);
        return 1;
    }
    
    close(fd);
    
    // 读取文件
    fd = open("test.txt", O_RDONLY);
    if (fd == -1) {
        perror("读取时 open 失败");
        return 1;
    }
    
    char buffer[100];
    ssize_t bytes_read = read(fd, buffer, sizeof(buffer) - 1);
    if (bytes_read > 0) {
        buffer[bytes_read] = '\0';
        printf("文件内容: %s\n", buffer);
    }
    
    close(fd);
    
    // 文件统计
    struct stat fileStat;
    if (stat("test.txt", &fileStat) == 0) {
        printf("文件大小: %ld 字节\n", fileStat.st_size);
        printf("是文件: %s\n", S_ISREG(fileStat.st_mode) ? "是" : "否");
        printf("是目录: %s\n", S_ISDIR(fileStat.st_mode) ? "是" : "否");
    }
    
    // 目录操作
    DIR* dir = opendir(".");
    if (dir != NULL) {
        struct dirent* entry;
        printf("当前目录中的文件:\n");
        while ((entry = readdir(dir)) != NULL) {
            printf("  %s\n", entry->d_name);
        }
        closedir(dir);
    }
    
    // 进程信息
    char cwd[1024];
    if (getcwd(cwd, sizeof(cwd)) != NULL) {
        printf("当前工作目录: %s\n", cwd);
    }
    
    printf("进程 ID: %d\n", getpid());
    printf("父进程 ID: %d\n", getppid());
    
    // 清理
    unlink("test.txt");
    
    return 0;
}
```
</UniversalEditor>

## 6. 常见陷阱
- **竞态条件**：使用适当的同步机制
- **信号处理器安全性**：在信号处理器中只使用异步信号安全函数
- **资源泄漏**：始终关闭文件描述符并释放分配的内存
- **进程僵尸**：正确等待子进程
- **线程安全**：使用互斥锁和其他同步原语

## 7. 练习题
1. 编写一个程序，创建多个子进程并等待所有进程完成。
2. 实现一个可以执行命令的简单 shell。
3. 创建一个可以优雅处理多个信号的程序。
4. 编写一个执行并行计算的多线程程序。

## 8. 性能分析
- **进程创建**：比线程创建更昂贵
- **进程间通信**：比线程间通信更慢
- **系统调用**：与用户空间操作相比有开销
- **信号处理**：异步且可能中断正常执行
- **线程同步**：互斥锁和信号量提供安全的并发访问

---

> **小结**：C 系统编程提供对操作系统功能的直接访问。理解进程管理、线程、信号处理和系统调用对构建系统级应用程序和工具至关重要。 